class Cell {

	public:
	int x;
	int y;
	int color;
	Cell head;
	Cell next;
	State state;
	HashMap<Integer, Boolean> qi;
	int idx;

	Cell(int x, int y, int color, Cell head, Cell next, State state, int idx) {
		this.x = x;
		this.y = y;
		this.color = color;
		this.head = head;
		this.next = next;
		this.state = state;
		this.qi = new HashMap<Integer, Boolean>();
		this.idx = idx;

		this.initQi();
	}

	void initQi() {
		int x = this.x;
		int y = this.y;
		if (y - 1 >= 0) {
			int idx = this.state.xy2idx(x, y - 1);
			if (!this.state.cellMap.containsKey(idx)) {
				this.qi.put(idx, true);
			}
		}
		if (y + 1 < this.state.boardWidth) {
			int idx = this.state.xy2idx(x, y + 1);
			if (!this.state.cellMap.containsKey(idx)) {
				this.qi.put(idx, true);
			}
		}
		if (x - 1 >= 0) {
			int idx = this.state.xy2idx(x - 1, y);
			if (!this.state.cellMap.containsKey(idx)) {
				this.qi.put(idx, true);
			}
		}
		if (x + 1 < this.state.boardWidth) {
			int idx = this.state.xy2idx(x + 1, y);
			if (!this.state.cellMap.containsKey(idx)) {
				this.qi.put(idx, true);
			}
		}

	}

	public boolean mergeBlock(Cell cell2) {

		boolean merged = false;

		if (cell2.qi.containsKey(this.idx)) {
			Cell cell = this;
			while (cell.next != null) {
				cell = cell.next;
			}
			cell.next = cell2;

			merged = true;
		}

		//		for (Map.Entry<Integer, Boolean> entry : cell2.qi.entrySet()) {
		//			int idx2 = entry.getKey();
		//
		//			if(idx2 == this.idx){
		//				Cell cell = this;
		//				while(cell.next!=null){
		//					cell = cell.next;
		//				}
		//				cell.next = cell2;
		//
		//				merged = true;
		//				break;
		//			}
		//		}

		if (merged) {

			cell2.qi.remove(this.idx);
			cell2.qi.putAll(this.qi);

			//			this.qi.forEach((idx, value2) -> {
			//				cell2.qi.put(idx, true);
			//			});

			this.qi = cell2.qi;
		}

		return merged;

	}

	public boolean deleteQi(Cell cell2) {

		boolean deleted = false;

		int deleteIdx = 0;

		if (this.qi.containsKey(cell2.idx)) {
			deleteIdx = cell2.idx;
			deleted = true;
		}
		//		for (Map.Entry<Integer, Boolean> entry : this.qi.entrySet()) {
		//			int idx = entry.getKey();
		//			if(idx == cell2.idx){
		//				deleteIdx = idx;
		//				deleted = true;
		//				break;
		//			}
		//		}
		if (deleted) {
			this.qi.remove(deleteIdx);
		}

		return deleted;
	}

	public void addQi(Cell cell3) {

		Cell cell2 = cell3;
		do {
			Cell cell = this;
			do {
				if (cell.idx - this.state.boardWidth == cell2.idx || cell.idx + this.state.boardWidth == cell2.idx || cell.x > 0 && cell.idx - 1 == cell2.idx || cell.x < this.state.boardWidth - 1 && cell.idx + 1 == cell2.idx) {
					this.qi.put(cell2.idx, true);
					break;
				}
				cell = cell.next;
			} while (cell != null);
			cell2 = cell2.next;
		} while (cell2 != null);

	}

	public int getQiCount() {
		return this.qi.size();
	}

	public int getCount() {

		int count = 1;
		Cell cell = this;
		while (cell.next != null) {
			count++;
			cell = cell.next;
		}
		return count;
	}

};